// SPDX-License-Identifier: GPL-3.0
// (c) Hare authors <https://harelang.org>

use fmt;
use hare::module;
use hare::unparse;
use io;
use memio;
use os;
use path;
use strings;

export fn main() void = {
	if (len(os::args) > 1 && os::args[1] == "-h") {
		fmt::errorln("usage:", os::args[0], "[<tag>...]")!;
		os::exit(0);
	};

	const ctx = module::context {
		harepath = os::tryenv("HAREPATH", "."),
		harecache = os::tryenv("HARECACHE", ".cache"),
		tags = os::args[1..],
	};
	let mods: []module::module = [];
	defer module::free_slice(mods);
	module::gather(&ctx, &mods, ["rt"])!;
	module::gather(&ctx, &mods, ["cmd", "hare"])!;

	let ids: [](str, str) = [];
	defer free(ids);
	defer for (let i = 0z; i < len(ids); i += 1) {
		free(ids[i].0);
		free(ids[i].1);
	};

	let with_libc = false;
	for (let i = 0z; i < len(ctx.tags); i += 1) {
		if (ctx.tags[i] == "libc") {
			with_libc = true;
		};
	};

	let tds = memio::dynamic();
	defer io::close(&tds)!;
	let objs = memio::dynamic();
	defer io::close(&objs)!;
	for (let i = 0z; i < len(mods); i += 1) {
		append(ids, (strings::join("_", mods[i].ns...),
			unparse::identstr(mods[i].ns)));
		fmt::fprintf(&tds, ` HARE_TD_{}=$(HARECACHE)/std/{}.td`,
			ids[i].1, ids[i].0)!;
		fmt::fprintf(&objs, ` $(HARECACHE)/std/{}.o`, ids[i].0)!;
	};

	let cwd = os::getcwd();
	let buf = path::init(mods[0].srcs.sc[0])!;
	fmt::println(`# generated by cmd/genbootstrap`)!;
	fmt::println(`# DO NOT EDIT BY HAND. run 'make bootstrap' to update`)!;
	fmt::printfln(`TDENV = env{}`, memio::string(&tds)!)!;
	fmt::printfln(`RTSCRIPT = {}`, path::trimprefix(&buf, cwd)!)!;
	fmt::printfln(`OBJS ={}`, memio::string(&objs)!)!;

	let deps = memio::dynamic();
	defer io::close(&deps)!;
	let sources = memio::dynamic();
	defer io::close(&sources)!;
	for (let i = 0z; i < len(mods); i += 1) {
		memio::reset(&deps);
		for (let j = 0z; j < len(mods[i].deps); j += 1) {
			fmt::fprintf(&deps, ` $(HARECACHE)/std/{}.td`,
				ids[mods[i].deps[j].0].0)!;
		};
		memio::reset(&sources);
		for (let j = 0z; j < len(mods[i].srcs.ha); j += 1) {
			path::set(&buf, mods[i].srcs.ha[j])!;
			fmt::fprint(&sources, "", path::trimprefix(&buf, cwd)!)!;
		};

		fmt::println()!;
		fmt::printfln(`{}_ha ={}`, ids[i].0, memio::string(&sources)!)!;
		fmt::printfln(`$(HARECACHE)/std/{}.ssa: $({}_ha){}`,
			ids[i].0, ids[i].0, memio::string(&deps)!)!;
		fmt::println("\t" `@mkdir -p -- "$(HARECACHE)/std"`)!;
		// fmt::println("\t" `@printf 'HAREC\t%s\n' "$@"`)!;
		fmt::printfln("\t" `@$(TDENV) $(HAREC) $(HARECFLAGS) {}-o $@ -t $(HARECACHE)/std/{}.td.tmp {} {} $({}_ha)`,
			if (i == len(mods) - 1 && with_libc) `-N "" ` else ``,
			ids[i].0,
			if (i == len(mods) - 1) `$(HARE_DEFINES)` else `-N`,
			if (i == len(mods) - 1) `` else ids[i].1, ids[i].0)!;
		if (len(mods[i].srcs.s) == 0) {
			continue;
		};

		memio::reset(&sources);
		for (let j = 0z; j < len(mods[i].srcs.s); j += 1) {
			path::set(&buf, mods[i].srcs.s[j])!;
			fmt::fprint(&sources, "", path::trimprefix(&buf, cwd)!)!;
		};

		fmt::println()!;
		fmt::printfln(`{}_s = $(HARECACHE)/std/{}.s{}`,
			ids[i].0, ids[i].0, memio::string(&sources)!)!;
		fmt::printfln(`$(HARECACHE)/std/{}.o: $({}_s)`, ids[i].0, ids[i].0)!;
		// fmt::println("\t" `@printf 'AS\t%s\n' "$@"`)!;
		fmt::printfln("\t" `@$(AS) $(ASFLAGS) -o $@ $({}_s)`, ids[i].0)!;
	};
};
